package com.erlang4j.internal.process;

import static com.erlang4j.api.Erlang4jMessageLanguage.atom;
import static com.erlang4j.api.Erlang4jMessageLanguage.binding;
import static com.erlang4j.api.Erlang4jMessageLanguage.state;
import junit.framework.TestCase;

import com.ericsson.otp.erlang.OtpErlangObject;
import com.ericsson.otp.erlang.OtpErlangPid;
import com.erlang4j.api.IGetData;
import com.erlang4j.api.adapters.MessageAdapter;
import com.erlang4j.api.exceptionHandler.SysoutExceptionHandler;
import com.erlang4j.api.exceptions.Erlang4jKeyNotFoundException;
import com.erlang4j.api.process.IProcessWithState;
import com.erlang4j.internal.adapters.MockAdapterWithStateChangeAdapter;
import com.erlang4j.internal.basicIo.MockBasicMailBox;
import com.erlang4j.internal.stateMachine.IStateDefinition;
import com.erlang4j.tests.Erlang4JTestHelper;

public class StateMachineChangingStateTest extends TestCase {

	private final MockAdapterWithStateChangeAdapter adapterMatchOneChangeB = new MockAdapterWithStateChangeAdapter("one", "B");
	private final MockAdapterWithStateChangeAdapter adapterMatchTwoChangeC = new MockAdapterWithStateChangeAdapter("two", "C");

	public void testProcess() {
		checkNameState(atom("one"), "B", adapterMatchOneChangeB, adapterMatchTwoChangeC);
		checkNameState(atom("two"), "C", adapterMatchOneChangeB, adapterMatchTwoChangeC);
	}

	public void testStateChangeIgnoredifException() {
		final StateMachine stateMachine = makeStateMachine(state("A", new MessageAdapter("one") {
			@Override
			public void process(IProcessWithState process, IGetData data) throws Exception {
				process.changeState("B");
				process.bind("NewKey", 1);
				throw new RuntimeException();
			}
		}), state("B"), state("C"));
		Erlang4JTestHelper.assertThrows(RuntimeException.class, new Runnable() {
			public void run() {
				stateMachine.process(atom("one"));
			}
		});
		assertEquals("A", stateMachine.getStateName());
		Erlang4JTestHelper.assertThrows(Erlang4jKeyNotFoundException.class, new Runnable() {
			public void run() {
				stateMachine.matchingBinding().getRaw("NewKey");
			}
		});
	}

	private void checkNameState(OtpErlangObject input, String expected, MockAdapterWithStateChangeAdapter adapterMatchOneChangeB2, MockAdapterWithStateChangeAdapter adapterMatchTwoChangeC2) {
		StateMachine stateMachine = makeStateMachine(state("A", adapterMatchOneChangeB, adapterMatchTwoChangeC), state("B"), state("C"));
		stateMachine.process(input);
		assertEquals(expected, stateMachine.getStateName());
	}

	private StateMachine makeStateMachine(IStateDefinition... states) {
		OtpErlangPid self = Erlang4JTestHelper.makePid();
		StateMachine stateMachine = new StateMachine(new MockBasicMailBox(self), new SysoutExceptionHandler(), binding("Initial", 1), states);
		return stateMachine;
	}

}
